﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlClient;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DataModels;
using ServiceUtilities;

namespace UtilTest
{
    /// <summary>
    /// Summary description for ServiceTest
    /// </summary>
    [TestClass]
    public class ServiceTest
    {
        public ServiceTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        // TODO: Remove this!!! Please!
        private string connectionString = "user id=nextrack; password=Pa55w0rd;server=WIN-SONO5SAHI60; Trusted_Connection=yes; database=Nextrack; connection timeout=30";

        /// <summary>
        ///A test for AddSong
        ///
        ///This test will add a song using the AddSong method, and set its party ID to a new Guid, which
        ///returns the SongID. Then it does a SQL query for the new song, and if the party ID returned
        ///matches the one passed to the method, the test is a success.
        ///</summary>
        [TestMethod()]
        public void AddSongTest()
        {
            

            Guid myPartyID = Guid.NewGuid();
            string connStr = connectionString;
            string partyID = myPartyID.ToString();
            string artist = "Michael Landau";
            string album = "Mike\'s BIG album!";
            string title = "Mike\'s BIG song!";

            string expected = partyID;
            string actual = string.Empty;

            // Invoke the method
            string songID = ServiceUtilities.ServiceUtilities.AddSong(connStr, partyID, artist, album, title);

            // See if we get the same song back from the database
            try
            {
                SqlConnection myConnection = new SqlConnection(connectionString);
                myConnection.Open();

                // see if we can get it
                string query = "SELECT * FROM Songs WHERE Song_ID=@Song_ID";
                using (SqlCommand command = new SqlCommand(query))
                {
                    command.Parameters.Add(new SqlParameter("Song_ID", songID));
                    SqlDataReader reader = command.ExecuteReader();
                    if(reader.Read())
                        actual = (string)reader["Party_ID"];
                }
                
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }
            
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void CreatePartyTest()
        {
            string connStr = connectionString; // TODO: Initialize to an appropriate value
            string description = "Sexy Party"; // TODO: Initialize to an appropriate value
            string accessCode = "1234abcd"; // TODO: Initialize to an appropriate value
            int accessLevel = 0; // TODO: Initialize to an appropriate value
            int votesPerUser = 0; // TODO: Initialize to an appropriate value
            int voteReplenish = 0; // TODO: Initialize to an appropriate value
            bool allowsRequests = false; // TODO: Initialize to an appropriate value
            CreatePartyData retVal = ServiceUtilities.ServiceUtilities.CreateParty(connStr, description, accessCode, accessLevel, votesPerUser, voteReplenish, allowsRequests);
            string expected = retVal.AccessCode;
            string actual = string.Empty;

            try
            {
                SqlConnection myConnection = new SqlConnection(connectionString);
                myConnection.Open();

                // see if we can get it
                string query = "SELECT * FROM Parties WHERE Song_ID=@Song_ID";
                using (SqlCommand command = new SqlCommand(query))
                {
                    command.Parameters.Add(new SqlParameter("Party_ID", expected));
                    SqlDataReader reader = command.ExecuteReader();
                    if(reader.Read())
                        actual = (string)reader["Access_Code"];
                }
                
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }

                
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for DownvoteSong
        ///</summary>
        [TestMethod()]
        public void DownvoteSongTest()
        {
            // TODO: DownvoteSong is NYI -- Finish this test next iteration
            Assert.Inconclusive("DownvoteSong method NYI");


            string connStr = string.Empty; // TODO: Initialize to an appropriate value
            string partyID = string.Empty; // TODO: Initialize to an appropriate value
            string songID = string.Empty; // TODO: Initialize to an appropriate value
            bool expected = false; // TODO: Initialize to an appropriate value
            bool actual;
            actual = ServiceUtilities.ServiceUtilities.DownvoteSong(connStr, partyID, songID);
            Assert.AreEqual(expected, actual);
            Assert.Inconclusive("Verify the correctness of this test method.");
            
        }

        /// <summary>
        ///A test for GetNowPlaying
        ///</summary>
        [TestMethod()]
        public void GetNowPlayingTest()
        {
            // before testing the method, create a party and song
            Guid partyID = new Guid();
            Guid expectedID = new Guid();

            try
            {
                SqlConnection myConnection = new SqlConnection(connectionString);
                myConnection.Open();

                //Create party
                using (SqlCommand command = new SqlCommand("INSERT INTO Parties VALUES(@ID, @Created_Time," +
                                "@End_Time, @Description, @Party_Owner, @Access_Code, @Access_Level," +
                                " @Votes_Per_User, @Vote_Replenish, @Allows_Requests, @Now_Playing)", myConnection))
                {
                    command.Parameters.Add(new SqlParameter("ID", partyID.ToString()));
                    command.Parameters.Add(new SqlParameter("Created_Time", DateTime.MinValue));
                    command.Parameters.Add(new SqlParameter("End_Time", DateTime.MinValue));
                    command.Parameters.Add(new SqlParameter("Description", ""));
                    command.Parameters.Add(new SqlParameter("Party_Owner", "Mike")); //TODO: add real user ID
                    command.Parameters.Add(new SqlParameter("Access_Code", "password1"));
                    command.Parameters.Add(new SqlParameter("Access_Level", 1));
                    command.Parameters.Add(new SqlParameter("Votes_Per_User", 1));
                    command.Parameters.Add(new SqlParameter("Vote_Replenish", 1));
                    command.Parameters.Add(new SqlParameter("Allows_Requests", false));
                    command.Parameters.Add(new SqlParameter("Now_Playing", expectedID.ToString()));
                    command.ExecuteNonQuery();
                }

                // Create Song
                using (SqlCommand command = new SqlCommand("INSERT INTO Songs VALUES(@Party_ID, @Song_ID," +
                                "@Title, @Artist, @Album, @Up_Vote_Stat, @Down_Vote_Stat, @Last_Played)", myConnection))
                {
                    command.Parameters.Add(new SqlParameter("Party_ID", partyID));
                    command.Parameters.Add(new SqlParameter("Song_ID", expectedID.ToString()));
                    command.Parameters.Add(new SqlParameter("Title", "aaa"));
                    command.Parameters.Add(new SqlParameter("Artist", "bbb"));
                    command.Parameters.Add(new SqlParameter("Album", "ccc"));
                    command.Parameters.Add(new SqlParameter("Up_Vote_Stat", 0));
                    command.Parameters.Add(new SqlParameter("Down_Vote_Stat", 0));
                    command.Parameters.Add(new SqlParameter("Last_Played", DateTime.MinValue));
                    command.ExecuteNonQuery();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                Assert.IsTrue(false);
            }

            string connStr = connectionString;
            string partyIDStr = partyID.ToString();
            SongData expected = new SongData();
            expected.SongID = expectedID.ToString();
            SongData actual;
            actual = ServiceUtilities.ServiceUtilities.GetNowPlaying(connStr, partyIDStr);
            Assert.AreEqual(expected.SongID, actual.SongID);
        }

        /// <summary>
        ///A test for GetQueue
        ///</summary>
        [TestMethod()]
        public void GetQueueTest()
        {
            string connStr = connectionString;
            string partyID = Guid.NewGuid().ToString(); 
           
            List<QueueData> returnedQueue;

            // add a song using the AddSong method
            string expected =  ServiceUtilities.ServiceUtilities.AddSong(connectionString, partyID, "Ben Liblit", "Software Engineering", "Harlem Shake");

            // use a SQL query to add the song to the queues table
            try
            {
                SqlConnection myConnection = new SqlConnection(connectionString);
                myConnection.Open();

                using (SqlCommand command = new SqlCommand("INSERT INTO Queues VALUES(@Party_ID, @Song_ID, @Up_Votes, @Down_Votes)", myConnection))
                {
                    command.Parameters.Add(new SqlParameter("Song_ID", expected));
                    command.Parameters.Add(new SqlParameter("Party_ID", partyID));
                    command.Parameters.Add(new SqlParameter("Up_Votes", 0));
                    command.Parameters.Add(new SqlParameter("Down_Votes", -1));
                    command.ExecuteNonQuery();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                Assert.Fail("Exception was thrown when trying to insert data into Queues table");
            }

            returnedQueue = ServiceUtilities.ServiceUtilities.GetQueue(connStr, partyID);

            string actual = returnedQueue[0].Song.SongID;
            Assert.AreEqual(expected, actual);
            
        }

        /// <summary>
        ///A test for RemoveSong
        ///</summary>
        [TestMethod()]
        public void RemoveSongTest()
        {
            string connStr = connectionString;
            string partyID = Guid.NewGuid().ToString();
            string songID = Guid.NewGuid().ToString();
            try
            {
                SqlConnection connection = new SqlConnection(connStr);

                // add a song using an SQL query
                using (SqlCommand command = new SqlCommand("INSERT INTO Songs VALUES(@Party_ID, @Song_ID," +
                                    "@Title, @Artist, @Album, @Up_Vote_Stat, @Down_Vote_Stat, @Last_Played)", connection))
                {
                    command.Parameters.Add(new SqlParameter("Party_ID", partyID));
                    command.Parameters.Add(new SqlParameter("Song_ID", songID.ToString()));
                    command.Parameters.Add(new SqlParameter("Title", "Remove song test"));
                    command.Parameters.Add(new SqlParameter("Artist", "Remove song test"));
                    command.Parameters.Add(new SqlParameter("Album", "rage"));
                    command.Parameters.Add(new SqlParameter("Up_Vote_Stat", 0));
                    command.Parameters.Add(new SqlParameter("Down_Vote_Stat", 0));

                    command.Parameters.Add(new SqlParameter("Last_Played", DateTime.Now.AddYears(1)));
                    command.ExecuteNonQuery();
                }

                // remove the song via the method
                ServiceUtilities.ServiceUtilities.RemoveSong(connStr, partyID, songID);

                // lookup the song -- it shouldn't exist!
                using (SqlCommand command = new SqlCommand("SELECT * FROM Songs WHERE Song_ID=@Song_ID"))
                {
                    SqlDataReader reader = command.ExecuteReader();
                    if (reader.HasRows)
                        Assert.Fail("Song still exists in DB after calling RemoveSong");
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                Assert.Fail("An exception was thrown");
            }

             
        }

        /// <summary>
        ///A test for UpdateNowPlaying
        ///</summary>
        [TestMethod()]
        public void UpdateNowPlayingTest()
        {
            // TODO: This test will require a little more setup -- We can do this in a future iteration
            Assert.Inconclusive("UpdateNowPlaying NYI");

            string connStr = string.Empty; // TODO: Initialize to an appropriate value
            string partyID = string.Empty; // TODO: Initialize to an appropriate value
            string songID = string.Empty; // TODO: Initialize to an appropriate value
            bool expected = false; // TODO: Initialize to an appropriate value
            bool actual;
            actual = ServiceUtilities.ServiceUtilities.UpdateNowPlaying(connStr, partyID, songID);
            Assert.AreEqual(expected, actual);
            Assert.Inconclusive("Verify the correctness of this test method.");
        }

        /// <summary>
        ///A test for UpvoteSong
        ///</summary>
        [TestMethod()]
        public void UpvoteSongTest()
        {
            string connStr = string.Empty; // TODO: Initialize to an appropriate value
            string songID = Guid.NewGuid().ToString();
            int expected = 1; // TODO: Initialize to an appropriate value
            int actual = 0;

            // insert song into DB

            try
            {
                SqlConnection connection = new SqlConnection(connectionString);
                connection.Open();

                using (SqlCommand command = new SqlCommand("INSERT INTO Songs VALUES(@Party_ID, @Song_ID," +
                    "@Title, @Artist, @Album, @Up_Vote_Stat, @Down_Vote_Stat, @Last_Played)", connection))
                {
                    command.Parameters.Add(new SqlParameter("Party_ID", "UPVOTE_SONG_TEST"));
                    command.Parameters.Add(new SqlParameter("Song_ID", songID.ToString()));
                    command.Parameters.Add(new SqlParameter("Title", "UPVOTE_SONG_TEST"));
                    command.Parameters.Add(new SqlParameter("Artist", "Michael Landau"));
                    command.Parameters.Add(new SqlParameter("Album", "Mike\'s BIG Album"));
                    command.Parameters.Add(new SqlParameter("Up_Vote_Stat", 0));
                    command.Parameters.Add(new SqlParameter("Down_Vote_Stat", 0));
                    command.Parameters.Add(new SqlParameter("Last_Played", DateTime.MinValue));

                    command.ExecuteNonQuery();
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }

            ServiceUtilities.ServiceUtilities.UpvoteSong(connStr, "UPVOTE_SONG_TEST", songID);

            // see if it succeeded
            try
            {
                SqlConnection connection = new SqlConnection(connectionString);
                connection.Open();

                using (SqlCommand command = new SqlCommand("SELECT * FROM Songs WHERE Song_ID=@Song_ID"))
                {
                    command.Parameters.Add(new SqlParameter("Song_ID", songID.ToString()));

                    SqlDataReader reader = command.ExecuteReader();
                    if (reader.Read())
                        expected = (int)reader["Up_Vote_Stat"];
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
            }

            Assert.AreEqual(expected, actual);
        }
    }
}
